﻿using System;
using System.Data;
using System.Data.Common;
using System.Collections.Generic;
using System.Text;

using RAD.LightOne.Data;

namespace RAD.LightOne
{
    #region Documentation
    /// <summary>
    /// Calsse que provê funcionalidades de reflexão em banco de dados, pode possuir comportamento transacional 
    /// ou não, dependedo do contexto de sua utilização, uma vez que as operações de reflexão de schema são obtidas 
    /// via comandos sql muitas vezes inseridos em um contexto maior onde outros comandos estão envolvidos.
    /// </summary>
    #endregion Documentation
    internal sealed class SchemaHelper
    {
        #region Constructors
        private SchemaHelper() { }
        #endregion Constructors

        #region Methods
        #region Documentation
        /// <summary>
        /// Retorna uma tabela com a representação do esquema de uma outra.
        /// </summary>
        /// <param name="tableName">nome da tabela q será buscada no banco de dados.</param>
        /// <returns>DataTable contendo o esquema.</returns>
        #endregion Documentation
        public static DataTable GetTableSchema(string tableName)
        {
            if (tableName == null) throw new ArgumentNullException("tableName");

            //caso o esquema já esteja em cache, o retorno se dá por ele.
            Configuration config = Configuration.Instance();
            Cache.SchemaCache cache = new Cache.SchemaCache();
            if (cache.ContainsKey(tableName)) return cache[tableName];

            const string sql = "SELECT * FROM {0}{1}{2}";
            try
            {
                DBEngine dbe = DBEngine.GetInstance();
                dbe.CommandText = DBEngine.EvalReplaceSchema(string.Format(sql, config.QuotePrefix, tableName, config.QuoteSuffix));
                DataTable schema = dbe.ResolveSchema(tableName);
                cache.Add(schema);
                return schema;
            }
            catch (Exception e)
            {
                throw new System.Data.InvalidExpressionException(new StringBuilder().AppendFormat(
                    "A tabela {0} não pode ser selecionada.", tableName).ToString(), e);
            }
        }

        #region Documentation
        /// <summary>
        /// Retorna uma tabela com a representação do esquema de uma outra, transacionado.
        /// </summary>
        /// <param name="tableName">nome da tabela q será buscada no banco de dados.</param>
        /// <returns>DataTable contendo o esquema.</returns>
        /// <param name="trx">transação utilizada na captura do esquema da tabela.</param>
        #endregion Documentation
        public static DataTable GetTableSchema(IDbTransaction trx, string tableName)
        {
            if (tableName == null) throw new ArgumentNullException("SchemaCatcher.GetTableSchema");

            //caso o esquema já esteja em cache, o retorno se dá por ele.
            Cache.SchemaCache cache = new Cache.SchemaCache();
            if (cache.ContainsKey(tableName)) return cache[tableName];

            
            try
            {
                DBEngine dbe = DBEngine.GetInstance(trx);

                Configuration config = Configuration.Instance();
                const string sql = "SELECT * FROM {0}{1}{2}";
                dbe.CommandText = DBEngine.EvalReplaceSchema(string.Format(sql, config.QuotePrefix, tableName, config.QuoteSuffix));
                dbe.CommandType = CommandType.Text;

                DataTable schema = dbe.ResolveSchema(tableName);
                cache.Add(schema);
                return schema;
            }
            catch (Exception e)
            {
                throw new System.Data.InvalidExpressionException(new StringBuilder().AppendFormat(
                    "A tabela {0} não pode ser selecionada.", tableName).ToString(), e);
            }
        }
        #endregion
    }
}
